package com.teamwings.ctrls;

import cn.hutool.core.lang.Filter;
import com.alibaba.fastjson.JSONObject;
import com.teamwings.common.constant.FormConstant;
import com.teamwings.common.exception.ServiceException;
import com.teamwings.common.vo.Result;
import com.teamwings.config.druid.DruidDBConfig;
import com.teamwings.modules.design.vo.FormVo;
import com.teamwings.modules.page.service.IPageService;
import lombok.Data;
import org.apache.logging.log4j.util.TriConsumer;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Data
public abstract class FormComponent implements GenerateField {
    protected String type;

    protected String fieldType = "";
    protected String fieldDefaultLength = "";
    //
    public boolean beField = true;
    public boolean beLayout = false;

    protected String label;
    // model 和 key 有可能会成为字段名，所以不能含有“-”字符
    protected String model;
    protected String key;
    /*
    Field 在子类进行声明，会初始化类型相关的两个属性，字段名字，会在setModel()进行设置
     */
    //protected Field field = new Field();
    protected Map<String, Object> options;

    // 内部附加字段
    /*
    以字典为例
    {
        'id' : {
            valid: false,       // 是否有效
            type: 'varchar',    // 字段类型
            length: 32          // 分配的长度
        },
        'name': {
            valid: true,
            type: 'varchar',
            length: 20
        },
        'code': {
            valid: false,
            type: 'varchar',
            length: 20
        }
    }
     */
    protected Map<String, Map> internal;

    //// 暂时存储布局控件的相关数据 （这里存储：栅格布局【grid】，标签页布局【tabs】）
    //private List<Map<String, Object>> columns;
    //// 暂时存储表格布局控件【table】的相关数据
    //private List<Object> trs;
    //// 暂时存储卡片布局控件【card】的相关数据
    //private List<FormComponent> list;

    /*
        暂时不
        前端控件的属性可变且数量多，不会一一转化为控件类的属性，一些不常用的保存到集合当中。
     */
    // 除了options, columns, trs, list外，其它的属性
    //protected JSONObject otherProperties;
    //
    //public String getOtherPropertyItem(String name){
    //   return otherProperties.getString(name);
    //}

    // 返回布局控件子控件的JSON字符串
    public void setLayoutChildString(JSONObject obj) {
    }

    // 不需要的属性
    //private Integer maxLength;
    //protected Integer hasLabel;
    //protected String help;
    //protected String prefix;
    //protected String suffix;


    ///**
    // * 通过JSON实例化控件
    // * @param json
    // * @return
    // */
    //public static FormComponent instanceComponent(String json) {
    //
    //}

    /**
     * 获取变更的字段语句
     * @param bolAdd
     * @return
     */
//    public String getStatement(boolean bolAdd) {
//        // 拼接sql语句
//        String statement = "";
//        String isNullString = this.getIsAllowNullString();
//        Field field = this.newField();
//        if (field == null) {
//            return "";
//        }
//        if (!bolAdd) {
//            // 修改列类型
//            if (field.getIsAllowNull() != null && field.getIsAllowNull()) {
//                //  修改列类型时如果该列可以为空，后面不需要加"NULL"
//                statement =  field.getFieldName() +  " " + "TYPE" + " " + field.getFieldType() +
//                        " " + field.getFieldTypeValue();
//            } else {
//                statement =  field.getFieldName() +  " " + "TYPE" + " " + field.getFieldType() +
//                        " " + field.getFieldTypeValue() + " " + isNullString + " ";
//            }
//        } else {
//            // 生成数据表时的列
//            statement =  field.getFieldName() +  " " + field.getFieldType() +
//                    " " + field.getFieldTypeValue() + " " + isNullString + " ";
//        }
//        return statement;
//    }


    /**
     * 实现了GenerateField接口的组件，这些组件可以设置fieldType, filedName等值。 这个方法通过这些数据组装sql语句
     *
     * @param bolAdd false： 获取变更的字段语句   true： 获取生成数据表时的列
     * @return
     */
    public String getStatement(boolean bolAdd) {
        Field field = this.newField();
        return getStatement(bolAdd, field);
    }

    public String getStatement(boolean bolAdd, IField field) {
        String isNullString = this.getIsAllowNullString(field);

        // 拼接sql语句
        String statement = "";
        if (field == null) {
            return "";
        }
        if (DruidDBConfig.type.equalsIgnoreCase("kingbase")) {
            if (!bolAdd) {
                // 修改列类型
                if (field.getIsAllowNull() != null && field.getIsAllowNull()) {
                    //  修改列类型时如果该列可以为空，后面不需要加"NULL"
                    statement = field.getFieldName() + " " + "TYPE" + " " + field.getFieldType() +
                            " " + field.getFieldTypeValue();
                } else {
                    statement = field.getFieldName() + " " + "TYPE" + " " + field.getFieldType() +
                            " " + field.getFieldTypeValue() + " " + isNullString + " ";
                }
            } else {
                // 生成数据表时的列
                statement = field.getFieldName() + " " + field.getFieldType() +
                        " " + field.getFieldTypeValue() + " " + isNullString + " ";
            }
        } else if (DruidDBConfig.type.equalsIgnoreCase("mysql")) {
//            String[] needToInsertUtf8 = {};
            List<String> needToInsertUtf8 = Arrays.asList("VARCHAR", "TEXT");
            if (!bolAdd) {
                // 修改列类型
                if (field.getIsAllowNull() != null && field.getIsAllowNull()) {
                    if (needToInsertUtf8.contains(field.getFieldType())) {
                        //  修改列类型时如果该列可以为空，后面不需要加"NULL"
                        statement = "MODIFY COLUMN " + field.getFieldName() + " " + field.getFieldType() +
                                " " + field.getFieldTypeValue() + " CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ";
                    } else {
                        //  修改列类型时如果该列可以为空，后面不需要加"NULL"
                        statement = "MODIFY COLUMN " + field.getFieldName() + " " + field.getFieldType() +
                                " " + field.getFieldTypeValue() + " NULL DEFAULT NULL ";
                    }
                } else {
                    if (needToInsertUtf8.contains(field.getFieldType())) {
                        statement = "MODIFY COLUMN " + field.getFieldName() + " " + field.getFieldType() +
                                " " + field.getFieldTypeValue() + " CHARACTER SET utf8 COLLATE utf8_general_ci " + isNullString + " ";
                    } else {
                        statement = "MODIFY COLUMN " + field.getFieldName() + " " + field.getFieldType() +
                                " " + field.getFieldTypeValue() + " " + isNullString + " ";
                    }
                }
            } else {
                // 生成数据表时的列
                statement = field.getFieldName() + " " + field.getFieldType() +
                        " " + field.getFieldTypeValue() + " " + isNullString + " ";
            }
        } else {
            throw new ServiceException("构建建表sql语句失败：请根据数据库类型编写相应的建表代码");
        }
        return statement;
    }

    /**
     * 返回启用的内部字段配置
     * @return
     */
    public Map<String, Map> getInternalsValid() {
        Map<String, Map> internalConfig = this.getInternal();
        if (internalConfig == null) return null;

        Predicate<Map.Entry<String, Map>> fn = map -> (Integer) map.getValue().get("valid") == 1;
        Map<String, Map> ret = internalConfig.entrySet().stream()
                .filter(fn)
                .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));
        return ret;
    }

    /**
     * 在新增时进行内部字段处理
     */
    public void handleInternalFieldAdding(List<String> statementList, List<String> fieldsList) {
        Map<String, Map> internals = this.getInternalsValid();
        if (null == internals) return;
        // 本字段
        IField field = this.newField();
        for(Map.Entry entry : internals.entrySet()) {
            // 获取内部字段
            IField internalField = this.getInternalField(field,
                    entry.getKey() + "",
                    (Map<String, Object>)entry.getValue());
            // 添加到参数提供的List当中
            fieldsList.add(internalField.getFieldName());
            statementList.add(this.getStatement(true, internalField));
        }
    }

    /**
     * 在编辑时对内部字段进行处理
     * 内部字段是原父字段添加 key 值，作为内部字段名，统一为字符串字段varchar
     * 后面的value(Object)里面的 length 为设定最大长度
     *
     * @return
     */
    public void handleInternalFieldEditing(
            TriConsumer<String, FormComponent, IField> deisgnMapperHandler,
            Set<String> fieldsList) {
        // 本字段
        IField field = this.newField();
        // 内部字段配置
        Map<String, Map> internals = this.getInternalsValid();
        if (null == internals) return;
        for(Map.Entry entry : internals.entrySet()) {
            // 获取内部字段
            IField internalField = this.getInternalField(field,
                    entry.getKey() + "",
                    (Map<String, Object>)entry.getValue());
            // 添加到参数提供的List当中
            fieldsList.add(internalField.getFieldName());
            // 调用外部函数
            deisgnMapperHandler.accept(
                    internalField.getFieldName(),
                    this,
                    internalField
            );
        }
    }


    /**
     * 生成控件内部字段 Field 类
     * @param ctrlField     控件Field
     * @param key           内部字段key
     * @param fieldConfig   内部字段配置
     */
    public IField getInternalField(IField ctrlField, String key, Map<String, Object> fieldConfig) {
        String internalFieldName = ctrlField.getFieldName() + "__" + key;
        String[] propertys = new String[] {"type", "length"};
        if (!fieldConfig.containsKey(propertys[0])) {
            fieldConfig.put(propertys[0], "varchar");
        }
        if (!fieldConfig.containsKey(propertys[1])) {
            fieldConfig.put(propertys[1], "20");
        }
        IField field = new FieldInternal(
                internalFieldName,
                fieldConfig.get(propertys[0]) + "",
                fieldConfig.get(propertys[1]) + ""
        );
        return field;
    }


    public List<FormComponent> getFormComponentList() {
        return null;
    }

    // 获取是否运行为空的字符串
    // TODO
    //  是否为空可以从rules: [{ required: true }] 中获取
    protected String getIsAllowNullString(IField field) {
        String isNullString = "";
        // Field field = this.newField();
        if (field != null && field.getIsAllowNull() != null && field.getIsAllowNull()) {
            if (DruidDBConfig.type.equalsIgnoreCase("kingbase")) {
                isNullString = "NULL";
            } else if (DruidDBConfig.type.equalsIgnoreCase("mysql")) {
                isNullString = "NULL DEFAULT NULL";
            } else {
                throw new ServiceException("构建建表sql语句失败：请根据数据库类型编写相应的建表代码");
            }
        } else {
            isNullString = "NOT NULL";
        }
        return isNullString;
    }

    /**
     * 控件事件触发
     *
     * @param type
     * @param pageService
     * @param formDesignData
     * @param paramsData
     * @return
     */
    public Result<?> trigger(FormConstant.TRIGGER_TYPE type,
                             IPageService pageService, FormVo formDesignData,
                             Object paramsData) {
        return null;
    }

    /**
     * 获取数据字段长度
     * 一般是(20)， 有可能是Numeric(5,2)
     *
     * @return
     */
    public String getMaxLength() {
        String defaultLength = this.fieldDefaultLength;
        String key = "maxLength";
        if (this.options.containsKey(key)) {
            Object maxLength = this.options.get(key);
            if (maxLength != null) {
                return maxLength.toString();
            } else {
                return defaultLength;
            }
        } else {
            return defaultLength;
        }
    }

    /**
     * 设置model同时设置字段名
     *
     * @param model
     */
    public void setModel(String model) {
        this.model = model;
    }

    @Override
    public Field newField() {
        if (this.fieldType.equals("")) {
            return null;
        } else {
            return new Field(this);
        }
    }

    //@Override
    //public void setField(Field field) {
    //    if (field != null) {
    //        this.field = field;
    //    }
    //}

    ///**
    // * TODO 这里可以设置是否允许字段为空的，为了方便全部可为null也可以
    // * 根据 rules: [{required: true}] 来设置
    //  * @return
    // */
    //@Override
    //public Field getField() {
    //    return this.field;
    //}
}
